package com.lagou.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;

@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter  implements Filter {

    //记录每次方法时长的map
    Map<String,Long> invokeTimeMap = new ConcurrentHashMap<>();

    //待清理的延迟队列
    private final DelayQueue<TPMonitorFilter.TimeDelayed> timeDelayQueue = new DelayQueue<>();

    // 通过静态方法创建ScheduledExecutorService的实例
    private static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);


    //增加构造方法,在构造方法内初始化必要值
    public TPMonitorFilter(){
        //每5秒钟进行一次统计
        scheduledExecutorService.scheduleAtFixedRate(this::tp,0,5, TimeUnit.SECONDS);

        //进行清理时间过长的访问记录
        new Thread(()->{
            try {
                while (true){
                    String key = timeDelayQueue.take().key;
                    invokeTimeMap.remove(key);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long   startTime  = System.currentTimeMillis();
        try {
            // 执行方法
            return  invoker.invoke(invocation);
        } finally {
//            System.out.println("invoke time:"+(System.currentTimeMillis()-startTime) + "毫秒");
            String key = UUID.randomUUID().toString();
            invokeTimeMap.put(key,System.currentTimeMillis()-startTime);
            timeDelayQueue.offer(new TimeDelayed(System.currentTimeMillis()+1000*60l,key));
        }

    }

    /**
     * 进行TP数据的记录和打印
     */
    private void tp(){
        System.out.println("TP90:"+tp(90)+"  TP99:"+tp(99)+"  现在总计录数:"+invokeTimeMap.size());
    }

    private long tp(int percent) {
        List<Long> times = new ArrayList<>(invokeTimeMap.values());
        if(times.size()==0){
            return 0l;
        }
        float percentF = (float)percent/100;
        int index = (int)(percentF * times.size() - 1);
        times.sort(Long::compareTo);
        return times.get(index);
    }

    static class TimeDelayed implements Delayed{

        //需要清理的时间
        public long time;

        //需要清理的key
        public String key;

        public TimeDelayed(long time,String key){
            this.time=time;
            this.key=key;
        }

        @Override
        public long getDelay(TimeUnit timeUnit) {
            return timeUnit.convert(time-System.currentTimeMillis(),TimeUnit.MICROSECONDS);
        }

        @Override
        public int compareTo(Delayed delayed) {
            return Long.compare(getDelay(TimeUnit.MICROSECONDS),delayed.getDelay(TimeUnit.MICROSECONDS));
        }
    }

}
